Skip to content

Port UART reset fix from ESP-IDF #1408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 3, 2018
Merged

Conversation

chemicstry
Copy link
Contributor

@chemicstry chemicstry commented May 14, 2018

uartFlush() does not work after soft reset due to a hardware bug in ESP32. This was fixed in ESP-IDF by reading out all data from the buffers instead of using reset bits.

Using reset bits on UART1 also corrupts data in UART2. From technical reference manual:

UART2 doesn’t have any register to reset Tx_FIFO or Rx_FIFO, and the UART1_TXFIFO_RST and UART1_RXFIFO_RST in UART1 may impact the functioning of UART2. Therefore, these two registers in UART1 should only be used when the Tx_FIFO and Rx_FIFO in UART2 do not have any data. (R/W)

Hence UART should only be flushed by reading out.

ESP-IDF commits:
espressif/esp-idf@4052803
espressif/esp-idf@492db05

Fixes: #662

@chemicstry
Copy link
Contributor Author

And probably this one: #1314

@Rob58329
Copy link
Contributor

The above "Port UART reset fix from ESP-IDF #1408 [chemicstry]" fixed my ESP32 issue with corrupt Serial-ports after an “ESP.restart()” – very many thanks!

[PS. FYI: I was basically just using “while (Serial2.available()) Serial.write(Serial2.read()); while (Serial.available()) Serial2.write(Serial.read());” to transfer data to & from a GSM-module.]

@me-no-dev
Copy link
Member

@chemicstry will you please make the adjustment that I requested so I can merge this? Thanks :)

@chemicstry
Copy link
Contributor Author

@me-no-dev I do not see any comment where you requested adjustments. Could you repeat?

@me-no-dev
Copy link
Member

Not seeing this?

screen shot 2018-06-01 at 10 47 28

@sysizlayan
Copy link

sysizlayan commented Jun 1, 2018

I believe there is some missing parts which is needed in case of arduino.

  1. uart queue must be emptied after reading all of the characters.
    Without it, available functions returns non-zero value after flush.
  2. Flush needs to detach ISR, then attachs it afterwards.
    Otherwise while reading from the hardware buffer, ISR can read data to queue, since the process is not atomic.

I think disable and enable functions can do that. Something similar should suffice:

image

@negativekelvin
Copy link

@me-no-dev

Before you submit your review, your line comments are pending and only visible to you

@chemicstry
Copy link
Contributor Author

@me-no-dev At first I tried using uart->dev->fifo.rw_byte but compiler optimises dummy reading and it does not work unless I write some ugly assembler stuff. READ_PERI_REG macro is deeply integrated into IDF and I was unable to trace back how it actually works. Is there an example in arduino code on how to dummy read register or maybe you have a suggestion on how to do it?

Regarding the interrupts @sysizlayan. When uartFlush() is called during UART initialization, ISR is not enabled yet and it should not spit any data out. However, HardwareSerial::flush(), which uses uartFlush() has different behaviour and I think different function should be used. flush is intended to wait for data transfer to complete instead of reseting. Maybe uartFlush() should really be uartReset().

@me-no-dev
Copy link
Member

@negativekelvin holly cow! I was unaware of this... thanks for pointing out!

@chemicstry maybe use some dummy holder for the bytes?

uint8_t dummy;
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
  dummy = uart->dev->fifo.rw_byte;
}


// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
READ_PERI_REG(UART_FIFO_REG(uart->num));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use uart->dev->fifo.rw_byte instead of READ_PERI_REG(UART_FIFO_REG(uart->num))

@me-no-dev me-no-dev merged commit 12ca9e8 into espressif:master Jul 3, 2018
@brianrho
Copy link

As @chemicstry said, Serial.flush() behaves differently than expected of the Arduino API, clearing not only the TX buffer but also the RX buffer. Are there any plans to change this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How can I reset Serial2 / UART2?
6 participants